/**
 * 作者: 致心
 * 创建时间: 2020-08-19 10:01
 **/
import typeOfUtils from "@localModules/ZhiXinLib/utils/type-of-utils";
import {deepClone} from '@localModules/ZhiXinLib/utils/index'

const selfUtils = {
  _beginNumberLastNumberPPOrLess(beginNumber = '1', POL = false) {
    if (beginNumber.length > 1) {
      const strings = beginNumber.split('-')
      beginNumber = ''
      let number = Number(strings[strings.length - 1])
      if (POL) {
        number++
      } else {
        number--
      }
      strings[strings.length - 1] = String(number)
      strings.forEach(value => {
        beginNumber += (value + '-')
      })
      beginNumber = beginNumber.substring(0, beginNumber.lastIndexOf('-'))
    } else {
      if (POL) {
        // @ts-ignore
        beginNumber = String(++beginNumber)
      } else {
        // @ts-ignore
        beginNumber = String(--beginNumber)
      }
    }
    return beginNumber
  },

  /**
   * @Description: 这是转换以后返回的结果，结果里面保留list的所有数据，在用
   * 自己传进去的identifier作为标识去区分节点，比如：
   * 父节点为1
   * 子节点就是1-1,1-2,1-3的形式，以此类推
   * @Author: 致心
   * @Date: 2020/8/19 10:14
   */
  _listTree2List(tree = [], changeSource = false, field = '', identifier = '', beginNumber = '1') {
    if (Object.prototype.toString.call(tree) !== '[object Array]') {
      throw new Error('数据类型错误')
    }
    const result = []
    tree.forEach(value => {
      const resultItem = {}
      Object.keys(value).forEach(value1 => {
        if (value1 !== field) {
          resultItem[value1] = value[value1]
        }
      })
      resultItem[identifier] = beginNumber
      if (changeSource) {
        // @ts-ignore
        value[identifier] = beginNumber
      }
      beginNumber = this._beginNumberLastNumberPPOrLess(beginNumber, true)
      // @ts-ignore
      result.push(resultItem)
      // eslint-disable-next-line no-prototype-builtins
      // @ts-ignore
      if (value.hasOwnProperty(field) && value[field] && value[field].length > 0) {
        // @ts-ignore
        result.push(...this._listTree2List(value[field], changeSource, field, identifier, this._beginNumberLastNumberPPOrLess(beginNumber, false) + '-1'))
      }
    })
    return result
  },
  findIdentifier(list, find, identifier, grand) {
    let number = find[identifier].lastIndexOf('-')
    let s = find[identifier].substring(0, number)
    const result = []
    while (s) {
      if (grand) {
        // @ts-ignore
        result.unshift(list.find(i => i[identifier] === s))
        number = s.lastIndexOf('-')
        s = s.substring(0, number)
      } else {
        // @ts-ignore
        result.push(list.find(i => i[identifier] === s))
        break
      }
    }
    return result
  }
}

/**
 * @Description: 把树形list的转换成一个list
 * @param tree
 * @param changeSource 默认：false 是否在源树里面加入唯一标识
 * @param field 默认：children 传入属性名，树形list对象里面这个属性也为一个list
 * @param identifier 默认：childrenIndex 作为标识去区分节点，比如：父节点为1,子节点就是1-1,1-2,1-3的形式，以此类推
 * @Author: 致心
 * @Date: 2020/8/19 11:55
 * @returns {[]}
 */
export function listTree2List(tree = [], changeSource = false, field = 'children', identifier = 'childrenIndex') {
  if (field === '' || field.length < 1) {
    throw new Error('field数据错误')
  }
  if (identifier === '' || identifier.length < 1) {
    throw new Error('identifier数据错误')
  }
  return selfUtils._listTree2List(tree, changeSource, field, identifier)
}

/**
 * @Description :
 * @Author :致心
 * @Date :2020/12/30 15:55
 * @param tree {Array} 传入源数组或者是已经被这个文件里面的方法转化过的数组
 * @param source {Object} 传入要查找父对象的子对象
 * @param grand {Boolean} 是否查找曾级
 * @param isEqField {Array} 判断对象是否相等的依据字段，因为会先从树里面找到我们的对应的source，
 * 然后在找父对象，所以传入的字段必须在source里面要有
 * @param field {String} 树下面子数组的属性
 * @param identifier {String} 查找的标识
 * @returns {[]|*}
 */
export function findParent(tree = [], source = {}, grand = false, isEqField = ['id'], field = 'children', identifier = 'childrenIndex') {
  if (Object.prototype.toString.call(source) !== '[object Object]') {
    throw new Error('source数据错误')
  }
  for (let i = 0; i < isEqField.length; i++) {
    const item = isEqField[i]
    if (Object.keys(source).findIndex(j => j === item) === -1) {
      throw new Error('isEqField数据错误')
    }
  }
  let list = []
  // eslint-disable-next-line no-prototype-builtins
  if (!tree.hasOwnProperty(identifier)) {
    list = listTree2List(tree, false, field, identifier)
  } else {
    list = deepClone(tree)
  }
  const find = list.find(i => {
    let count = 0
    isEqField.forEach(j => {
      if (i[j] === source[j]) {
        count++
      }
    })
    return count === isEqField.length
  })
  if (!find) {
    throw new Error('source数据错误')
  }
  return selfUtils.findIdentifier(list, find, identifier, grand)
}

/**
 * @Description :
 * @Author :致心
 * @Date :2021/2/20 16:41
 * @param tree {Array} 传入源数组或者是已经被这个文件里面的方法转化过的数组
 * @param source {Object} 传入要查找父对象的子对象
 * @param grand {Boolean} 是否查找曾级
 * @param isEqField {Array} 判断对象是否相等的依据字段，因为会先从树里面找到我们的对应的source，
 * 然后在找父对象，所以传入的字段必须在source里面要有
 * @param field {String} 树下面子数组的属性
 * @param identifier {String} 查找的标识
 * @returns {*[]|*}
 */
export function findParentAndDelIdentifier(tree = [], source = {}, grand = false, isEqField = ['id'], field = 'children', identifier = 'childrenIndex') {
  const result = findParent(tree, source, grand, isEqField, field, identifier)
  result.forEach(i => {
    delete i[identifier]
  })
  return result
}

const listTreeUtils = {
  findParentAndDelIdentifier,
  findParent,
  listTree2List,
  /**
   * 过滤树形结构的数据,callback中返回true的保留
   * @param list
   * @param callback
   * @param children
   * @return {*[]}
   */
  filterTree(list = [], callback, children = 'children') {
    if (typeOfUtils.isEmpty(list)) {
      return []
    }
    if (typeOfUtils.isNotArray(list)) {
      console.error('list必须是一个数组')
      return []
    }
    const result = []
    list.forEach(i => {
      const item = deepClone(i)
      if (callback(item)) {
        if (typeOfUtils.isNotEmpty(item[children]) && typeOfUtils.isArray(item[children])) {
          item[children] = this.filterTree(item[children], callback, children)
        }
        // @ts-ignore
        result.push(item)
      }
    })
    return result
  },
  /**
   *
   * @param list 这个是已经被 listTree2List 转过的
   * @param children 要查找父级的子集
   * @param grand {Boolean} 是否查找曾级
   * @param identifier 这个是listTree2List转出来带有的 identifier
   * @return {*[]}
   */
  findParentByChildIndex(list = [], children = {}, grand = false, identifier = 'childrenIndex') {
    if (typeOfUtils.isEmpty(list)) {
      return []
    }
    if (typeOfUtils.isNotArray(list)) {
      console.error('list必须是一个数组')
      return []
    }
    if (typeOfUtils.isEmpty(children)) {
      return []
    }
    if (typeOfUtils.isEmpty(children[identifier])) {
      console.error(`children的${identifier}不能为空`)
      return []
    }
    const find = list.find(i => i[identifier] === children[identifier])
    return selfUtils.findIdentifier(list, find, identifier, grand)
  },
  /**
   *
   * @param list 这个是已经被 listTree2List 转过的
   * @param identifier 这个是listTree2List转出来带有的 identifier
   * @return {[]}
   */
  findLastChildren(list = [], identifier = 'childrenIndex') {
    if (typeOfUtils.isEmpty(list)) {
      return []
    }
    if (typeOfUtils.isNotArray(list)) {
      console.error('list必须是一个数组')
      return []
    }
    if (typeOfUtils.isEmpty(identifier)) {
      console.error(`${identifier}不能为空`)
      return []
    }
    let result = []
    result = list.filter(i => {
      const childrenId = i[identifier] + '-1'
      const find = list.find(j => j[identifier] === childrenId)
      return !find;
    })
    return result
  }
}

export default listTreeUtils
